package com.ccrfid.rmc6.service.video;

import com.ccrfid.rmc6.entity.video.VideoCameraEntity;
import com.ccrfid.rmc6.entity.video.VideoPlatformEntity;
import com.ccrfid.rmc6.pojo.hikartemis.resp.AppSecret;
import com.ccrfid.rmc6.pojo.open8200.Open8200ApiPath;
import com.ccrfid.rmc6.pojo.open8200.resp.*;
import com.ccrfid.rmc6.repository.video.VideoCameraRepository;
import com.ccrfid.rmc6.repository.video.VideoPlatformRepository;
import com.ccrfid.rmc6.util.JsonUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.hikvision.artemis.sdk.ArtemisHttpUtil;
import com.hikvision.artemis.sdk.config.ArtemisConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Transactional
public class Open8200ServiceImpl implements Open8200Service {
    private static final Logger logger = LoggerFactory.getLogger(Open8200ServiceImpl.class);
    private static final String contentType = "application/json;charset=UTF-8";
    private static final int defaultPageSize = 100;

    @Autowired
    private VideoPlatformRepository videoPlatformRepository;
    @Autowired
    private VideoCameraRepository videoCameraRepository;

    private String initArtemisConfig(VideoPlatformEntity platformEntity) {
        ArtemisConfig.appKey = platformEntity.getUsername();
        ArtemisConfig.appSecret = platformEntity.getPasswd();

        String serviceUrl = platformEntity.getSyncServiceUrl();
        int index = serviceUrl.indexOf("//");
        if (index > 0 && index < 7) {
            ArtemisConfig.host = serviceUrl.substring(index + 2);
            return serviceUrl.substring(0, index + 2);
        } else {
            ArtemisConfig.host = platformEntity.getIp() + ":" + platformEntity.getPort();
            return "https://";
        }
    }

    @Override
    public AppSecret getAppSecret(VideoPlatformEntity platformEntity) {
        String pathKey = initArtemisConfig(platformEntity);

        Map<String, String> path = new HashMap<>();
        path.put(pathKey, Open8200ApiPath.security_app_secret.replace("{appKey}", platformEntity.getUsername()));
        String responseBody = ArtemisHttpUtil.doGetArtemis(path, null, null, null);
        logger.debug("getAppSecret response: {}", responseBody);

        ResultData<AppSecret> response = JsonUtil.INSTANCE.readValue(responseBody, new TypeReference<ResultData<AppSecret>>() {});
        if (response.getCode().equals("0")) {
            AppSecret appSecret = response.getData();
            appSecret.setAppKey(platformEntity.getUsername());
            appSecret.setServerIp(platformEntity.getIp());
            appSecret.setServerPort(platformEntity.getPort());
            return appSecret;
        } else {
            logger.error("getAppSecret response: {}", responseBody);
            return null;
        }
    }

    @Override
    public List<DataOrg> getAllOrgs(VideoPlatformEntity platformEntity) {
        List<DataOrg> list = new ArrayList<>();
        String pathKey = initArtemisConfig(platformEntity);
        Map<String, String> path = new HashMap<>();
        path.put(pathKey, Open8200ApiPath.get_org);
        int pageNo = 0;
        int pageSize = defaultPageSize;
        ResultData<List<DataOrg>> result = getOrgPage(path, pageNo, pageSize);
        if (result != null) {
            if (result.getData() != null && result.getData().size() > 0) {
                list.addAll(result.getData());
            }
            PageDto page = result.getPage();
            while (page != null && page.getTotal() > (page.getPage() + 1) * page.getSize()) {
                pageNo++;
                result = getOrgPage(path, pageNo, pageSize);
                if (result != null) {
                    if (result.getData() != null && result.getData().size() > 0) {
                        list.addAll(result.getData());
                    }
                    page = result.getPage();
                } else {
                    break;
                }
            }
        }
        return list;
    }

    private ResultData<List<DataOrg>> getOrgPage(Map<String, String> path, int pageNo, int pageSize) {
        Map<String, String> querys = new HashMap<>();
        querys.put("start", Integer.toString(pageNo));
        querys.put("size", Integer.toString(pageSize));
        String responseBody = ArtemisHttpUtil.doGetArtemis(path, querys, null, null);
        logger.debug("getOrgPage response: {}", responseBody);
        ResultData<List<DataOrg>> result =
                JsonUtil.INSTANCE.readValue(responseBody, new TypeReference<ResultData<List<DataOrg>>>() {});
        if (result.getCode().equals("200")) {
            return result;
        } else {
            return null;
        }
    }

    @Override
    public List<DataOrg> getSubOrgs(VideoPlatformEntity platformEntity, String unitCode) {
        String pathKey = initArtemisConfig(platformEntity);
        Map<String, String> path = new HashMap<>();
        path.put(pathKey, Open8200ApiPath.get_sub_org);
        Map<String, String> querys = new HashMap<>();
        querys.put("unitCode", unitCode);
        String responseBody = ArtemisHttpUtil.doGetArtemis(path, querys, null, null);
        logger.debug("getSubOrgs response: {}", responseBody);
        ResultData<List<DataOrg>> result =
                JsonUtil.INSTANCE.readValue(responseBody, new TypeReference<ResultData<List<DataOrg>>>() {});
        if (result.getCode().equals("200")) {
            return result.getData();
        } else {
            return null;
        }
    }

    @Override
    public List<DataCamera> getAllCameras(VideoPlatformEntity platformEntity) {
        List<DataCamera> list = new ArrayList<>();
        String pathKey = initArtemisConfig(platformEntity);
        Map<String, String> path = new HashMap<>();
        path.put(pathKey, Open8200ApiPath.get_cameras);
        int pageNo = 0;
        int pageSize = defaultPageSize;
        ResultData<List<DataCamera>> result = getCameraPage(path, pageNo, pageSize, null);
        if (result != null) {
            if (result.getData() != null && result.getData().size() > 0) {
                list.addAll(result.getData());
            }
            while (true) {
                pageNo++;
                result = getCameraPage(path, pageNo, pageSize, null);
                if (result != null && result.getData() != null && result.getData().size() > 0) {
                    list.addAll(result.getData());
                    if (result.getData().size() < defaultPageSize) {
                        break;
                    }
                } else {
                    break;
                }
            }
        }
        list.stream().forEach(dataCamera -> setCameraDetail(platformEntity, dataCamera));
        return list;
    }

    @Override
    public List<DataCamera> getSubCameras(VideoPlatformEntity platformEntity, String orgIndexCode) {
        List<DataCamera> list = new ArrayList<>();
        String pathKey = initArtemisConfig(platformEntity);
        Map<String, String> path = new HashMap<>();
        path.put(pathKey, Open8200ApiPath.get_cameras_by_org);
        int pageNo = 0;
        int pageSize = defaultPageSize;
        ResultData<List<DataCamera>> result = getCameraPage(path, pageNo, pageSize, orgIndexCode);
        if (result != null) {
            if (result.getData() != null && result.getData().size() > 0) {
                list.addAll(result.getData());
            }
            while (true) {
                pageNo++;
                result = getCameraPage(path, pageNo, pageSize, orgIndexCode);
                if (result != null && result.getData() != null && result.getData().size() > 0) {
                    list.addAll(result.getData());
                    if (result.getData().size() < defaultPageSize) {
                        break;
                    }
                } else {
                    break;
                }
            }
        }
        list.stream().forEach(dataCamera -> setCameraDetail(platformEntity, dataCamera));
        return list;
    }

    private ResultData<List<DataCamera>> getCameraPage(Map<String, String> path, int pageNo, int pageSize, String treeNode) {
        Map<String, String> querys = new HashMap<>();
        querys.put("start", Integer.toString(pageNo));
        querys.put("size", Integer.toString(pageSize));
        if (treeNode != null) {
            querys.put("start", Integer.toString(pageNo));
        }
        String responseBody = ArtemisHttpUtil.doGetArtemis(path, querys, null, null);
        logger.debug("getCameraPage response: {}", responseBody);
        ResultData<List<DataCamera>> result =
                JsonUtil.INSTANCE.readValue(responseBody, new TypeReference<ResultData<List<DataCamera>>>() {});
        if (result.getCode().equals("200")) {
            return result;
        } else {
            return null;
        }
    }

    private void setCameraDetail(VideoPlatformEntity platformEntity, DataCamera camera) {
        String pathKey = initArtemisConfig(platformEntity);
        Map<String, String> path = new HashMap<>();
        path.put(pathKey, Open8200ApiPath.get_camera_detail);
        Map<String, String> querys = new HashMap<>();
        querys.put("indexCode", camera.getIndexCode());
        try {
            String responseBody = ArtemisHttpUtil.doGetArtemis(path, querys, null, null);
            logger.debug("getCameraDetail response: {}", responseBody);
            ResultData<List<DataCamera>> result =
                    JsonUtil.INSTANCE.readValue(responseBody, new TypeReference<ResultData<List<DataCamera>>>() {});
            if (result.getCode().equals("200") && result.getData().size() > 0) {
                DataCamera tmp = result.getData().get(0);
                camera.setAppCode(tmp.getAppCode());
                camera.setCascadeCode(tmp.getCascadeCode());
                camera.setChanNum(tmp.getChanNum());
                camera.setDeviceIdx(tmp.getDeviceIdx());
                camera.setId(tmp.getId());
                camera.setMatrixCode(tmp.getMatrixCode());
                camera.setOriginalIndexCode(tmp.getOriginalIndexCode());
                camera.setPrivCodes(tmp.getPrivCodes());
                camera.setRecLocation(tmp.getRecLocation());
                camera.setRecordPos(tmp.getRecordPos());
                camera.setSeqIdx(tmp.getSeqIdx());
                camera.setTreeNodeIndexCode(tmp.getTreeNodeIndexCode());
                camera.setTreeNodePath(tmp.getTreeNodePath());
                camera.setTypeCode(tmp.getTypeCode());
            }
        } catch (Exception ex) {
            logger.error("getCameraDetail err: {}", ex.getMessage());
            ex.printStackTrace();
        }
    }

    @Override
    public String getPreviewURL(String cameraIndexCode, String protocol, Integer streamType) {
        VideoCameraEntity videoCameraEntity = videoCameraRepository.getByCameraSn(cameraIndexCode);
        if (videoCameraEntity != null) {
            VideoPlatformEntity platformEntity = videoPlatformRepository.getTopByIpAndPlatformVersion(
                    videoCameraEntity.getIp(), videoCameraEntity.getCameraVersion());
            if (platformEntity != null) {
                String pathKey = initArtemisConfig(platformEntity);
                Map<String, String> path = new HashMap<>();
                path.put(pathKey, Open8200ApiPath.get_preview);
                Map<String, String> querys = new HashMap<>();
                querys.put("cameraIndexCode", cameraIndexCode);
                if (protocol != null) {
                    switch (protocol) {
                        case "rtsp":
                            querys.put("protocol", "0");
                            break;
                        case "hls":
                            querys.put("protocol", "1");
                            break;
                        case "rtmp":
                            querys.put("protocol", "2");
                            break;
                    }
                }
                if (streamType != null) {
                    querys.put("subStream", streamType == 0 ? "0" : "1");
                }
                String responseBody = ArtemisHttpUtil.doGetArtemis(path, querys, null, null);
                logger.debug("getPreviewUrl response: {}", responseBody);
                ResultPreviewUrl previewUrl = JsonUtil.INSTANCE.readValue(responseBody, ResultPreviewUrl.class);
                if (previewUrl.getCode().equals("200")) {
                    return previewUrl.getPlayrealUrl();
                }
            }
        }
        return "";
    }

    @Override
    public String getPlaybackURL(String cameraIndexCode, String protocol,
                                 Timestamp beginTime, Timestamp endTime, Integer recordLocation) {
        VideoCameraEntity videoCameraEntity = videoCameraRepository.getByCameraSn(cameraIndexCode);
        if (videoCameraEntity != null) {
            VideoPlatformEntity platformEntity = videoPlatformRepository.getTopByIpAndPlatformVersion(
                    videoCameraEntity.getIp(), videoCameraEntity.getCameraVersion());
            if (platformEntity != null) {
                String pathKey = initArtemisConfig(platformEntity);
                Map<String, String> path = new HashMap<>();
                path.put(pathKey, Open8200ApiPath.get_playback);
                Map<String, String> querys = new HashMap<>();
                querys.put("cameraIndexCode", cameraIndexCode);
                if (beginTime != null) {
                    querys.put("beginTime", Long.toString(beginTime.getTime() / 1000));
                }
                if (endTime != null) {
                    querys.put("endTime", Long.toString(endTime.getTime() / 1000));
                }
                if (recordLocation != null) {
                    querys.put("recordPos", recordLocation.toString());
                }
                String responseBody = ArtemisHttpUtil.doGetArtemis(path, querys, null, null);
                logger.debug("getPlaybackURL response: {}", responseBody);
                ResultData<DataPlaybackUrl> result =
                        JsonUtil.INSTANCE.readValue(responseBody, new TypeReference<ResultData<DataPlaybackUrl>>() {});
                if (result.getCode().equals("200")) {
                    return result.getData().getTotalTimeUrl();
                }
            }
        }
        return "";
    }

    @Override
    public String getVideoClientPlayUrl(String playType, List<Long> cameraIdList, Integer miniUI, Integer clear,
                                        Integer wndSelect, Integer httpsFlag, Timestamp startTime, Timestamp stopTime) {
        if (cameraIdList != null && cameraIdList.size() > 0) {
            VideoCameraEntity videoCameraEntity = videoCameraRepository.getById(cameraIdList.get(0));
            if (videoCameraEntity != null) {
                VideoPlatformEntity platformEntity = videoPlatformRepository.getTopByIpAndPlatformVersion(
                        videoCameraEntity.getIp(), videoCameraEntity.getCameraVersion());
                AppSecret appSecret = getAppSecret(platformEntity);
                if (appSecret != null) {
                    String url = "HikVideoClient://VersionTag:artemis;ReqType:" + playType +
                            ";SvrIp:" + appSecret.getServerIp() + ";SvrPort:" + appSecret.getServerPort() +
                            ";AppKey:" + appSecret.getAppKey() + ";AppSecret:" + appSecret.getAppSecret() +
                            ";Time:" + appSecret.getTime() + ";TimeSecret:" + appSecret.getTimeSecret() + ";";
                    if (miniUI != null) {
                        url += "MiniUI:" + miniUI + ";";
                    }
                    if (clear != null) {
                        url += "Clear:" + clear + ";";
                    } else {
                        url += "Clear:1;";
                    }
                    if (wndSelect != null) {
                        url += "WndSelect:" + wndSelect + ";";
                    }
                    if (httpsFlag != null) {
                        url += "httpsflag:" + httpsFlag + ";";
                    } else {
                        url += "httpsflag:1;";
                    }
                    if (cameraIdList.size() == 1) {
                        url += "WndCount:1;";
                    } else if (cameraIdList.size() > 1 && cameraIdList.size() <= 4) {
                        url += "WndCount:4;";
                    } else if (cameraIdList.size() > 4) {
                        url += "WndCount:9;";
                    }
                    url += "CamList:" + getCameraList(cameraIdList, startTime, stopTime) + ";";
                    return url;
                }
            }
        }
        return "";
    }

    private String getCameraList(List<Long> cameraIdList, Timestamp startTime, Timestamp stopTime) {
        List<VideoCameraEntity> cameraList = videoCameraRepository.getAllByIdIn(cameraIdList);
        if (cameraList != null && cameraList.size() > 0) {
            String content = "";
            String postfix = "";
            if (startTime != null && stopTime != null) {
                postfix = "_" + (startTime.getTime() / 1000) + "_" + (stopTime.getTime() / 1000);
            }
            for (VideoCameraEntity cameraEntity : cameraList) {
                content += cameraEntity.getCameraSn() + postfix + ",";
            }
            return content.substring(0, content.length() - 1);
        }
        return "";
    }
}
